package com.kongjs.application.controller;


import cn.hutool.http.useragent.Browser;
import cn.hutool.http.useragent.Platform;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.kongjs.application.convert.MenusConverter;
import com.kongjs.application.model.dto.*;
import com.kongjs.application.model.vo.*;
import com.kongjs.application.service.AuthService;
import com.kongjs.application.util.MenuTreeBuilder;
import com.kongjs.common.rest.annotation.Rest;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Slf4j
@Rest
@RestController
@RequestMapping("/auth")
public class AuthController {
    @Resource
    private MenusConverter menusConverter;
    @Resource
    private AuthService authService;

    private void setUa(AccountDTO accountDTO, HttpServletRequest request) {
        UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
        Platform platform = userAgent.getPlatform();
        Browser browser = userAgent.getBrowser();
        accountDTO.setLoginIp(request.getRemoteAddr());
        accountDTO.setPlatform(platform.getName());
        accountDTO.setBrowser(browser.getName());
    }

    @PostMapping("/login")
    public TokenVO login(@RequestBody @Validated AccountVO vo, HttpServletRequest request) {
        AccountDTO accountDTO = new AccountDTO();
        accountDTO.setTenantCode(vo.getTenantCode());
        accountDTO.setUsername(vo.getUsername());
        accountDTO.setPassword(vo.getPassword());
        setUa(accountDTO, request);
        TokenDTO dto = authService.login(accountDTO);
        return new TokenVO(dto.getAccessToken(), dto.getRefreshToken());
    }

    @PostMapping("/register")
    public Boolean register(@RequestBody @Validated AccountVO vo, HttpServletRequest request) {
        AccountDTO accountDTO = new AccountDTO();
        accountDTO.setTenantCode(vo.getTenantCode());
        accountDTO.setUsername(vo.getUsername());
        accountDTO.setPassword(vo.getPassword());
        setUa(accountDTO, request);
        return authService.register(accountDTO);
    }

    @PostMapping("/logout")
    public void logout(TokenVO vo) {
        TokenDTO dto = new TokenDTO();
        dto.setAccessToken(vo.getAccessToken());
        dto.setRefreshToken(vo.getRefreshToken());
        authService.logout(dto);
    }

    @PostMapping("/refresh")
    public TokenVO refresh(@RequestBody String refreshToken) {
        TokenDTO dto = authService.refresh(refreshToken);
        return new TokenVO(dto.getAccessToken(), null);
    }


    @GetMapping("/info")
    public UserInfoVo info() {
        UserInfoDTO dto = authService.info();
        if (ObjectUtils.isEmpty(dto)) {
            return null;
        }
        UserInfoVo vo = new UserInfoVo();
        vo.setAvatar(dto.getAvatar());
        vo.setUserId(dto.getUserId());
        vo.setUsername(dto.getUsername());
        vo.setNickname(dto.getNickname());
        vo.setHomePath(dto.getHomePath());
        return vo;
    }

    @GetMapping("/tenants")
    public List<OptionVO> tenants() {
        List<TenantDTO> tenantDTOS = authService.tenants();
        return tenantDTOS.stream().map(tenantDTO -> new OptionVO(tenantDTO.getTenantName(), tenantDTO.getTenantCode())).toList();
    }

    @GetMapping("/menus")
    public List<QueryMenuVO> menus() {
        List<QueryMenuDTO> dtos = authService.menus();
        List<QueryMenuVO> vos = dtos.stream()
                .map(dto -> {
                    QueryMenuVO vo = menusConverter.toVo(dto);
                    QueryMenuMetaVO metaVO = menusConverter.toVo(dto.getMeta());
                    vo.setMeta(metaVO);
                    return vo;
                })
                .toList();
        return MenuTreeBuilder.buildTree(vos);
    }

    @GetMapping("/csrf")
    public CsrfToken csrf(CsrfToken csrfToken) {
        return csrfToken;
    }

}
